package cn.yh.nft.turbo.chain.domain.service;

import cn.yh.nft.turbo.chain.domain.constant.ChainOperateStateEnum;
import cn.yh.nft.turbo.chain.domain.entity.ChainOperateInfo;
import cn.yh.nft.turbo.chain.infrastructure.mapper.ChainOperateInfoMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @ClassName: ChainOperateInfoService
 * @Author: 草莓爱上啵啵
 */

@Service
public class ChainOperateInfoService extends ServiceImpl<ChainOperateInfoMapper, ChainOperateInfo> {

    @Autowired
    private ChainOperateInfoMapper chainOperateInfoMapper;

    /**
     * 插入信息方法
     * 该方法用于将特定业务信息插入到区块链操作信息表中
     *
     * @param chainType 链类型，表示信息所属的区块链类型
     * @param bizId 业务ID，用于唯一标识一笔业务
     * @param bizType 业务类型，描述业务的种类
     * @param operateType 操作类型，说明对业务进行的操作
     * @param param 参数，业务操作的附加参数
     * @param operationId 操作ID，外部业务系统发起操作的ID
     * @return 如果信息插入成功，返回插入信息的ID；如果插入失败，返回null
     */
    public Long insertInfo(String chainType, String bizId, String bizType, String operateType, String param, String operationId) {
        // 创建ChainOperateInfo对象，用于存储区块链操作信息
        ChainOperateInfo operateInfo = new ChainOperateInfo();
        // 设置操作时间为当前时间
        operateInfo.setOperateTime(new Date());
        // 设置链类型
        operateInfo.setChainType(chainType);
        // 设置业务ID
        operateInfo.setBizId(bizId);
        // 设置业务类型
        operateInfo.setBizType(bizType);
        // 设置操作类型
        operateInfo.setOperateType(operateType);
        // 设置参数
        operateInfo.setParam(param);
        // 设置外部业务ID
        operateInfo.setOutBizId(operationId);
        // 设置操作状态为处理中
        operateInfo.setState(ChainOperateStateEnum.PROCESSING);

        // 尝试保存区块链操作信息
        boolean ret = save(operateInfo);
        // 如果保存成功，返回操作信息的ID
        if (ret) {
            return operateInfo.getId();
        }

        // 如果保存失败，返回null
        return null;
    }

    /**
     * 更新操作结果信息
     *
     * @param id 操作信息的唯一标识
     * @param state 当前操作的状态
     * @param result 操作的结果信息
     * @return 返回更新操作是否成功
     *
     * 本方法用于更新链路操作信息的状态和结果根据提供的ID获取操作信息对象，
     * 然后更新其状态和结果字段最后尝试更新数据库中的对应记录
     */
    public boolean updateResult(Long id, ChainOperateStateEnum state, String result){
        // 根据ID获取操作信息对象
        ChainOperateInfo operateInfoDO = getById(id);
        // 设置操作结果信息
        operateInfoDO.setResult(result);
        // 设置操作状态
        operateInfoDO.setState(state);
        // 更新数据库中的对应记录
        return updateById(operateInfoDO);
    }

    /**
     * 根据外部业务ID查询链路操作信息
     *
     * @param bizId     业务ID，用于标识特定的业务
     * @param bizType   业务类型，用于区分不同的业务类型
     * @param outBizId  外部业务ID，用于匹配特定的外部业务记录
     * @return          返回匹配的链路操作信息对象，如果没有匹配的记录则返回null
     */
    public ChainOperateInfo queryByOutBizId(String bizId, String bizType, String outBizId) {
        // 创建查询条件构建器
        QueryWrapper<ChainOperateInfo> queryWrapper =  new QueryWrapper<>();
        // 添加查询条件：业务ID等于bizId
        queryWrapper.eq("biz_id", bizId);
        // 添加查询条件：业务类型等于bizType
        queryWrapper.eq("biz_type", bizType);
        // 添加查询条件：外部业务ID等于outBizId
        queryWrapper.eq("out_biz_id", outBizId);

        // 执行查询并获取结果列表
        List<ChainOperateInfo> retList = list(queryWrapper);

        // 检查查询结果是否为空
        if (CollectionUtils.isEmpty(retList)){
            // 如果结果为空，则返回null
            return null;
        }

        // 返回查询结果中的第一条记录
        return retList.get(0);
    }

    /**
     * 根据操作状态分页查询操作信息
     *
     * @param state 操作的状态，用于筛选查询结果
     * @param pageSize 每页的记录数，用于限制查询结果的数量
     * @param minId 查询的最小记录ID，用于分页查询的起点
     * @return 返回一个ChainOperateInfo对象的列表，包含符合查询条件的操作信息
     */
    public List<ChainOperateInfo> pageQueryOperateInfoByState(String state, int pageSize,Long minId) {
        // 创建一个QueryWrapper对象，用于构建查询条件
        QueryWrapper<ChainOperateInfo> wrapper = new QueryWrapper<>();

        // 添加查询条件：根据状态筛选记录
        wrapper.eq("state", state);

        // 添加排序条件：根据创建时间升序排列记录
        wrapper.orderBy(true, true, "gmt_create");

        // 添加查询条件：记录ID大于等于minId，用于分页查询
        wrapper.ge("id", minId);

        // 添加查询条件：限制查询结果的数量，实现分页功能
        wrapper.last("limit " + pageSize);

        // 执行查询，并返回查询结果列表
        return this.list(wrapper);
    }

    /**
     * 根据状态查询最小的ID
     *
     * 该方法通过调用ChainOperateInfoMapper中的相应方法，来获取具有指定状态的最小ID
     * 主要用于在大量数据中快速定位到特定状态的起始记录，以提高查询效率
     *
     * @param state 状态值，用于筛选记录
     * @return 返回具有指定状态的最小ID如果不存在这样的记录，则返回null
     */
    public Long queryMinIdByState(String state){
        return chainOperateInfoMapper.queryMinIdByState(state);
    }

    /**
     * 根据ID删除实体
     *
     * @param id 待删除实体的ID
     */
    public void delete(Long id){
        removeById(id);
    }
}
